
<template>
  <div class="player" v-show="playList.length">
    <transition name='up'>
      <div class="layer-player" v-show="fullScreen">
        <div class="background">
          <img width="100%" height='100%' :src="imgSrc" alt="">
        </div>
        <nav-bar>
          <div class="back" slot="left" @click="back(false)">
            <i class="icon-back"></i>
          </div>
          <div slot="center" class="now-wrap layer-song">{{currentSong.name}}</div>
        </nav-bar>
        <div class="middle" @touchstart='middleTouchStart' @touchmove='middleTouchMove' @touchend='middleTouchEnd'>
          <div class="middle-l" ref="middleL">
            <div class="cd-wrapper">
              <img :class="rotate" class="cd-image" :src="imgSrc" alt="">
            </div>
            <p class="playing-lyric" v-if="playingLyric">{{playingLyric}}</p>
            <p class="no-lyric" v-else>此歌曲暂无歌词</p>
          </div>
          <scroll v-show='currentLyricLiens' :list='currentLyricLiens' ref="lyricList" class="middle-r">
            <div>
              <p class="text" v-for="(v,i) in currentLyricLiens" :key="i" :class="[currentLineNum === i? 'current':'']" ref="lyricLine" @dblclick="playCurrentLyric(v)">{{v.txt}}</p>
              <p class="no-lyric" v-show="!playingLyric">此歌曲暂无歌词</p>
            </div>
          </scroll>
        </div>
        <div class="bottom">
          <div class="dot-wrapper">
            <span class="dot" :class="[currentShow ==='cd' ? 'active' :'']"></span>
            <span class="dot" :class="[currentShow ==='lyric' ? 'active' :'']"></span>
          </div>
          <div class="progress-wrapper">
            <span class="time">{{currentTime | format}}</span>
            <progress-bar class="song-progress" :percent='percent' @percentChange='percentChange' />
            <span class="time">{{currentSong.interval |format}}</span>
          </div>
          <div class="icon-wrapper">
            <i :class="modeIcon" @click="changeMode"></i>
            <i class="icon-prev" @click="changeIndex(-1)"></i>
            <i :class="playIcon" @click="changePlaying"></i>
            <i class="icon-next" @click="changeIndex(1)"></i>
            <i :class="favoriteIcon" @click='toggleFavorite'></i>
          </div>
        </div>
      </div>
    </transition>
    <div class="mini-player" v-show="!fullScreen" @click="back(true)">
      <img :class="rotate" class='mini-image' :src="imgSrc" alt="">
      <h2 class="mini-song-name no-wrap">{{currentSong.name}}</h2>
      <i :class="miniIcon" @click.stop='changePlaying'></i>
      <i class="icon-playlist" @click.stop="showPlayList"> </i>
    </div>
    <play-list ref="playListRef" @changeMode='changeMode' />
    <audio :src="audioSrc" ref='audio' @canplay="ready" @error="error" @timeupdate="updateTime" @ended="end" hidden></audio>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import Lyric from 'lyric-parser'
import progressBar from 'components/progress-bar/progressBar'
import scroll from 'components/base/Scroll'
import playList from 'components/playList/PlayList'

import { playerMixin } from 'common/js/mixin'
import NavBar from 'components/common/navbar'
import { getMusicUrl, getLyric } from 'api/music'
import { shuffle } from 'common/js/random'

export default {
  components: { NavBar, playList, scroll, progressBar },
  mixins: [playerMixin],
  name: 'player',
  data() {
    return {
      audioSrc: '', // 歌曲播放地址
      songReady: false, // 歌曲是在否准备
      playMode: {
        // 播放模式
        sequence: 0, // 顺序
        loop: 1, // 循环
        random: 2 // 随机
      },
      currentTime: 0, // 音频目前播放时间
      currentLyric: null, // 歌词对象
      currentLineNum: 0, // 当前播放那个的歌词行数
      playingLyric: '', // 当前播放的歌词
      currentShow: 'cd', // 当前展示的是歌词还是cd
      touch: {},
      miniIcon: '',
      playIcon: '',
      rotate: ''
    }
  },

  computed: {
    ...mapState(['mode', 'currentIndex', 'playing', 'sequenceList', 'playList', 'fullScreen', 'historyPlay']),
    imgSrc() {
      return this.currentSong.mid ? `https://y.gtimg.cn/music/photo_new/T002R300x300M000${this.currentSong.album.mid}.jpg` : ''
    },
    percent() {
      return this.currentTime / this.currentSong.interval
    },
    currentLyricLiens() {
      return this.currentLyric && this.currentLyric.lines
    },
    modeIcon() {
      let str = ''
      switch (this.mode) {
        case 0:
          str = 'icon-sequence'
          break
        case 1:
          str = 'icon-loop'
          break
        case 2:
          str = 'icon-random'
          break
      }
      return str
    }
  },
  filters: {
    format(val) {
      val = val | 0
      const mm = (val / 60) | 0
      let ss = val % 60 | 0
      ss = ss >= 10 ? ss : '0' + ss
      return `${mm}:${ss}`
    }
  },
  watch: {
    currentSong(val) {
      const mid = val.mid
      if (!mid) {
        return
      }
      this.loadAudioSrc(mid)
      if (this.currentLyric) {
        this.currentLyric.stop()
        this.originLyric()
      }
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.loadLyric(mid)
      }, 1000)
      this.local(this.historyPlay, 'hisplayPlay')
    },
    playing(play) {
      this.getPlayIcon(play)
      const audio = this.$refs.audio
      play ? audio.play() : audio.pause()
    },
    currentIndex() {
      this.getFavoriteIcon()
    }
  },
  methods: {
    playCurrentLyric(line) {
      let curTime = line.time
      this.$refs.audio.currentTime = curTime / 1000
      if (this.currentLyric) {
        this.currentLyric.seek(curTime)
      }
    },
    back(flag) {
      this.$store.commit('setFullScreen', flag)
    },
    showPlayList() {
      this.$refs.playListRef.show()
    },
    percentChange(percent) {
      const curTime = this.currentSong.interval * percent
      this.$refs.audio.currentTime = curTime
      if (this.currentLyric) {
        this.currentLyric.seek(curTime * 1000)
      }
    },
    updateTime(e) {
      this.currentTime = e.target.currentTime
    },
    error() {
      this.songReady = false
    },
    ready() {
      this.songReady = true
      this.$store.commit('setPlaying', true)
      this.$refs.audio.play()
    },
    end() {
      if (this.mode === this.playMode.loop) {
        this.loop()
      } else {
        this.changeIndex(1)
      }
    },
    async loadAudioSrc(mid) {
      const { data } = await getMusicUrl(mid)
      if (data.result === 100) {
        this.audioSrc = data.data[mid]
      } else {
        this.audioSrc = ''
        this.changeIndex(1)
      }
    },
    async loadLyric(mid) {
      const { data } = await getLyric(mid)
      if (data.result === 100) {
        this.currentLyric = new Lyric(data.data.lyric, this.handleLyric)
        this.currentLyric.play()
      } else {
        this.originLyric()
      }
    },
    handleLyric({ lineNum, txt }) {
      this.currentLineNum = lineNum
      if (lineNum > 5) {
        const lineEl = this.$refs.lyricLine[lineNum - 5]
        this.$refs.lyricList.scrollToElement(lineEl, 1000)
      } else {
        this.$refs.lyricList.scrollTo(0, 0, 1000)
      }
      this.playingLyric = txt
    },
    originLyric() {
      this.currentLyric = null
      this.playingLyric = ''
      this.currentLineNum = 0
    },

    changeMode() {
      const mode = (this.mode + 1) % 3
      this.$store.commit('setMode', mode)

      if (mode === this.playMode.random) {
        let list = shuffle(this.sequenceList)
        this.$store.commit('setPlayList', list)
      }
    },
    loop() {
      this.$refs.audio.currentTime = 0
      if (this.currentLyric) {
        this.currentLyric.seek(0)
      }
    },
    changeIndex(i) {
      let len = this.playList.length
      if (len === 1) {
        this.loop()
      } else {
        this.$store.commit('setPlaying', false)
        let idx = this.currentIndex + i
        if (idx < 0) {
          idx = len - 1
        } else if (idx > len) {
          idx = 0
        }
        this.$store.commit('setCurrentIndex', idx)
      }
    },
    middleTouchMove(e) {
      const t = this.touch
      if (t.inited) {
        const touch = e.touches[0]

        const detailY = touch.pageY - t.pageY
        let detailX = touch.pageX - t.pageX

        if (Math.abs(detailY) > Math.abs(detailX)) return

        if (detailX < -50) {
          this.$refs.middleL.style.display = 'none'
          this.$refs.lyricList.$el.style.left = '0'
          this.currentShow = 'lyric'
        } else {
          this.$refs.middleL.style.display = ''
          this.$refs.lyricList.$el.style.left = '100%'
          this.currentShow = 'cd'
        }
      }
    },

    middleTouchStart(e) {
      this.touch.inited = true
      const touch = e.touches[0]
      this.touch.pageX = touch.pageX
      this.touch.pageY = touch.pageY
    },
    middleTouchEnd() {
      this.touch.inited = false
    },
    changePlaying() {
      if (this.songReady) {
        const flag = this.playing ? false : true
        this.$store.commit('setPlaying', flag)
      }
    },
    getPlayIcon(play) {
      this.rotate = play ? 'play' : 'play  pause'
      this.miniIcon = play ? 'icon-pause-mini' : 'icon-play-mini'
      this.playIcon = play ? 'icon-pause' : 'icon-play'
    }
  }
}
</script>

<style scoped>
.up-enter,
.up-leave-to {
  transform: translateY(100);
}
.up-enter-active,
.up-leave-active {
  transition: all 0.5 ease;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}
.play {
  animation: rotate 20s linear infinite;
}
.pause {
  animation-play-state: paused;
}
.layer-player {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 50;
  background-color: #222;
}
.back {
  transform: rotate(-90deg);
}
.background {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  filter: blur(20px);
  opacity: 0.6;
  z-index: -5;
}
.middle {
  position: relative;
  width: 100%;
  height: 450px;
}
.middle-l {
  height: 100%;
}
.cd-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 400px;
}
.cd-image {
  width: 220px;
  height: 220px;
  border-radius: 50%;
  border: 10px solid rgba(255, 255, 255, 0.1);
}
.middle-r {
  position: absolute;
  margin: 10px 0;
  top: 0;
  left: 100%;
  width: 100%;
  height: 400px;
  overflow: hidden;
  text-align: center;
  font-size: 14px;
}
.text {
  line-height: 30px;
  color: rgba(255, 255, 255, 0.3);
}
.current {
  color: violet;
  font-size: 16px;
}
.playing-lyric,
.no-lyric {
  font-size: 15px;
  text-align: center;
  line-height: 30px;
}
.dot-wrapper {
  display: flex;
  justify-content: center;
  line-height: 30px;
}
.dot {
  width: 8px;
  height: 8px;
  border-radius: 5px;
  margin: 0 5px;
  background-color: #fff;
}
.active {
  width: 16px;
}
.icon-favorite {
  color: var(--color-theme-r);
}
.progress-wrapper {
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-align: center;
  height: 50px;
}
.time {
  width: 40px;
  font-size: 12px;
}
.song-progress {
  width: 240px;
}
.icon-wrapper {
  padding: 10px 30px;
  display: flex;
  color: var(--color-theme);
  justify-content: space-between;
  align-items: center;
  font-size: 34px;
}
.icon-play,
.icon-pause {
  font-size: 40px;
}
.bottom {
  margin-top: 10px;
}
.mini-player {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: #333;
  height: 60px;
  display: flex;
  align-items: center;
  z-index: 180;
  box-shadow: 0 -1px 1px rgba(255, 255, 255, 0.1);
  box-sizing: border-box;
}
.mini-image {
  width: 50px;
  height: 50px;
  margin: 0 10px;
  border-radius: 50%;
}
.mini-song-name {
  width: 190px;
}
.mini-player i {
  font-size: 40px;
  margin: 0 8px;
  color: var(--color-theme);
}
</style>